package com.zjhn.ds.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zjhn.ds.common.BizResult;
import com.zjhn.ds.common.PageResult;
import com.zjhn.ds.domain.entity.erp.Operator;
import com.zjhn.ds.domain.entity.jlw.DailyProduceStatistics;
import com.zjhn.ds.domain.entity.jlw.MachineChange;
import com.zjhn.ds.domain.entity.jlw.MaintenanceInfo;
import com.zjhn.ds.domain.entity.jlw.Proofing;
import com.zjhn.ds.domain.entity.jlw.ReportRecord;
import com.zjhn.ds.domain.entity.jlw.SpotCheck;
import com.zjhn.ds.domain.entity.jlw.UserWorkStation;
import com.zjhn.ds.domain.entity.jlw.WorkshopClasses;
import com.zjhn.ds.domain.vo.CapacityStatisticsOutVo;
import com.zjhn.ds.domain.vo.CapacityStatisticsVo;
import com.zjhn.ds.domain.vo.ChangTimeVo;
import com.zjhn.ds.domain.vo.MaintenanceChangeVo;
import com.zjhn.ds.domain.vo.MonthDailyDataVo;
import com.zjhn.ds.domain.vo.StaffInfoVo;
import com.zjhn.ds.domain.vo.StationVo;
import com.zjhn.ds.mapper.DailyProduceStatisticsMapper;
import com.zjhn.ds.mapper.MachineChangeMapper;
import com.zjhn.ds.mapper.MaintenanceInfoMapper;
import com.zjhn.ds.mapper.OperatorMapper;
import com.zjhn.ds.mapper.ProofingMapper;
import com.zjhn.ds.mapper.ReportRecordMapper;
import com.zjhn.ds.mapper.SpotCheckMapper;
import com.zjhn.ds.mapper.UserWorkStationMapper;
import com.zjhn.ds.mapper.WorkshopClassesMapper;
import com.zjhn.ds.param.CapacityStatisticsParam;
import com.zjhn.ds.param.MaintenanceChangePageParam;
import com.zjhn.ds.param.MonthDailyStatisticsParam;
import com.zjhn.ds.param.UpdateCapacityStatisticsParam;
import com.zjhn.ds.param.WeavingStaffPageParam;
import com.zjhn.ds.service.DailyProduceStatisticsService;
import com.zjhn.ds.service.MaintenanceChangeService;
import com.zjhn.ds.utils.CommonUtil;
import com.zjhn.ds.utils.base.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * TODO 类作用描述
 *
 * @author sxt
 * @date 2024/8/16
 */
@Slf4j
@Service
public class MaintenanceChangeServiceImpl implements MaintenanceChangeService {

    @Resource
    private MaintenanceInfoMapper maintenanceInfoMapper;

    @Resource
    private MachineChangeMapper machineChangeMapper;

    @Resource
    private ReportRecordMapper reportRecordMapper;

    @Resource
    private CommonUtil commonUtil;

    @Resource
    private OperatorMapper operatorMapper;

    @Resource
    private SpotCheckMapper spotCheckMapper;

    @Resource
    private ProofingMapper proofingMapper;

    @Resource
    private DailyProduceStatisticsMapper dailyProduceStatisticsMapper;

    @Resource
    private DailyProduceStatisticsService dailyProduceStatisticsService;

    @Resource
    private WorkshopClassesMapper workshopClassesMapper;

    @Resource
    private UserWorkStationMapper userWorkStationMapper;

    /**
     * 按条件分页查询改机/维修信息
     *
     * @param param
     * @return
     */
    @Override
    public BizResult<PageResult<MaintenanceChangeVo>> page(MaintenanceChangePageParam param) {
        PageResult<MaintenanceChangeVo> res = PageResult.<MaintenanceChangeVo>builder()
                .pages(0L)
                .size(0L)
                .current(0L)
                .total(0L)
                .record(new ArrayList<>())
                .build();

        if (param.getType() == 1) {
            // 改机
            QueryWrapper<MachineChange> queryWrapper = new QueryWrapper<>();
            if (StringUtils.isNotBlank(param.getStationCode()))
                queryWrapper.eq("station_code", param.getStationCode());
            queryWrapper.orderByAsc("finish").orderByDesc("change_time");
            if (StringUtils.isNotBlank(param.getBeginTime()))
                queryWrapper.ge("change_time", param.getBeginTime());
            if (StringUtils.isNotBlank(param.getEndTime()))
                queryWrapper.le("finish_time", param.getEndTime());

            Page<MachineChange> page = machineChangeMapper
                    .selectPage(new Page<>(param.getCurrent(), param.getSize()), queryWrapper);

            Map<String, String> realNameMap = new HashMap<>();
            List<MachineChange> records = page.getRecords();
            if (!records.isEmpty()) {
                Set<String> userNos = records.stream().map(MachineChange::getChangeUserNo).collect(Collectors.toSet());
                if (!userNos.isEmpty()) {
                    List<Operator> operators = operatorMapper.selectList(new QueryWrapper<Operator>()
                            .in("UserNo", userNos)
                            .eq("IsDeleted", 0)
                    );

                    if (!operators.isEmpty())
                        realNameMap.putAll(operators.stream().collect(Collectors.toMap(Operator::getUserNo, Operator::getRealName)));
                }
            }

            res.setPages(page.getPages());
            res.setSize(page.getSize());
            res.setCurrent(page.getCurrent());
            res.setTotal(page.getTotal());
            res.setRecord(page.getRecords().stream()
                    .map(c -> MaintenanceChangeVo.builder()
                            .id(c.getId())
                            .stationId(c.getStationId())
                            .stationCode(c.getStationCode())
                            .startTime(c.getChangeTime())
                            .endTime(c.getFinishTime())
                            .spendTime(c.getSpendTime())
                            .finish(c.getFinish())
                            .userNo(c.getChangeUserNo())
                            .realName(realNameMap.get(c.getChangeUserNo()))
                            .singleCost(c.getSingleCost())
                            .build())
                    .collect(Collectors.toList()));
        } else if (param.getType() == 2) {
            // 维修
            QueryWrapper<MaintenanceInfo> queryWrapper = new QueryWrapper<>();
            if (StringUtils.isNotBlank(param.getStationCode()))
                queryWrapper.eq("station_code", param.getStationCode());
            queryWrapper.orderByDesc("maintenance_time");
            if (StringUtils.isNotBlank(param.getBeginTime()))
                queryWrapper.ge("maintenance_time", param.getBeginTime());
            if (StringUtils.isNotBlank(param.getEndTime()))
                queryWrapper.le("finish_time", param.getEndTime());

            Page<MaintenanceInfo> page = maintenanceInfoMapper
                    .selectPage(new Page<>(param.getCurrent(), param.getSize()), queryWrapper);

            Map<String, String> realNameMap = new HashMap<>();
            List<MaintenanceInfo> records = page.getRecords();
            if (!records.isEmpty()) {
                Set<String> userNos = records.stream().map(MaintenanceInfo::getMaintenanceUserNo).collect(Collectors.toSet());
                if (!userNos.isEmpty()) {
                    List<Operator> operators = operatorMapper.selectList(new QueryWrapper<Operator>()
                            .in("UserNo", userNos)
                            .eq("IsDeleted", 0)
                    );

                    if (!operators.isEmpty())
                        realNameMap.putAll(operators.stream().collect(Collectors.toMap(Operator::getUserNo, Operator::getRealName)));
                }
            }


            res.setPages(page.getPages());
            res.setSize(page.getSize());
            res.setCurrent(page.getCurrent());
            res.setTotal(page.getTotal());
            res.setRecord(page.getRecords().stream()
                    .map(c -> MaintenanceChangeVo.builder()
                            .id(c.getId())
                            .stationId(c.getStationId())
                            .stationCode(c.getStationCode())
                            .startTime(c.getMaintenanceTime())
                            .endTime(c.getFinishTime())
                            .spendTime(c.getSpendTime())
                            .finish(c.getFinish())
                            .userNo(c.getMaintenanceUserNo())
                            .realName(realNameMap.get(c.getMaintenanceUserNo()))
                            .build())
                    .collect(Collectors.toList()));
        } else {
            // 打样

            QueryWrapper<Proofing> queryWrapper = new QueryWrapper<>();
            if (StringUtils.isNotBlank(param.getStationCode()))
                queryWrapper.eq("station_code", param.getStationCode());
            queryWrapper.orderByDesc("proofing_time");
            if (StringUtils.isNotBlank(param.getBeginTime()))
                queryWrapper.ge("proofing_time", param.getBeginTime());
            if (StringUtils.isNotBlank(param.getEndTime()))
                queryWrapper.le("finish_time", param.getEndTime());

            Page<Proofing> page = proofingMapper
                    .selectPage(new Page<>(param.getCurrent(), param.getSize()), queryWrapper);

            Map<String, String> realNameMap = new HashMap<>();
            List<Proofing> records = page.getRecords();
            if (!records.isEmpty()) {
                Set<String> userNos = records.stream().map(Proofing::getProofingUserNo).collect(Collectors.toSet());
                if (!userNos.isEmpty()) {
                    List<Operator> operators = operatorMapper.selectList(new QueryWrapper<Operator>()
                            .in("UserNo", userNos)
                            .eq("IsDeleted", 0)
                    );

                    if (!operators.isEmpty())
                        realNameMap.putAll(operators.stream().collect(Collectors.toMap(Operator::getUserNo, Operator::getRealName)));
                }
            }

            res.setPages(page.getPages());
            res.setSize(page.getSize());
            res.setCurrent(page.getCurrent());
            res.setTotal(page.getTotal());
            res.setRecord(page.getRecords().stream()
                    .map(c -> MaintenanceChangeVo.builder()
                            .id(c.getId())
                            .stationId(c.getStationId())
                            .stationCode(c.getStationCode())
                            .startTime(c.getProofingTime())
                            .endTime(c.getFinishTime())
                            .spendTime(c.getSpendTime())
                            .finish(c.getFinish())
                            .userNo(c.getProofingUserNo())
                            .realName(realNameMap.get(c.getProofingUserNo()))
                            .build())
                    .collect(Collectors.toList()));

        }

        return BizResult.success(res);
    }

    /**
     * 单日产能统计
     *
     * @param param
     * @return
     */
    @Override
    public BizResult<CapacityStatisticsOutVo> capacityStatistics(CapacityStatisticsParam param) {
        List<CapacityStatisticsVo> list = new ArrayList<>();

        String userNo = param.getUserNo();
        String date = param.getDate();

        WorkshopClasses workshopClass = commonUtil.getWorkshopClasses();

        // 多员工配置
        List<String> userNos = new ArrayList<>();
        if (StringUtils.isNotBlank(userNo))
            userNos.add(userNo);
        else {
            WeavingStaffPageParam weavingStaffPageParam = new WeavingStaffPageParam();
            weavingStaffPageParam.setCurrent(1L);
            weavingStaffPageParam.setSize(9999L);
            BizResult<PageResult<StaffInfoVo>> weavingStaff = this.weavingStaff(weavingStaffPageParam);
            if (weavingStaff.getData() != null && !weavingStaff.getData().getRecord().isEmpty())
                weavingStaff.getData().getRecord().stream().map(StaffInfoVo::getUserNo).forEach(userNos::add);
        }

        if (DateUtil.formatDateToString(new Date(), DateUtil.DATE_FORMAT).equals(date) && param.getWorkshopClassId().equals(workshopClass.getId())) {
            // 查询 当天 当前班次 指定员工的 机台产能统计
            date = DateUtil.formatDateToString(new Date(), DateUtil.DATE_FORMAT);
            queryCurrent(date, workshopClass, userNos, list);
        } else {
            // 指定日期 指定班次 机台产能统计
            if (date.equals(DateUtil.formatDateToString(new Date())) && workshopClass.getId().equals(param.getWorkshopClassId())) {
                queryCurrent(date, workshopClass, userNos, list);
            } else {
                List<DailyProduceStatistics> dailyProduceStatistics = dailyProduceStatisticsMapper.selectList(
                        new QueryWrapper<DailyProduceStatistics>()
                                .in("user_no", userNos)
                                .eq("date", date)
                                .eq("workshop_class_id", param.getWorkshopClassId()));
                if (!dailyProduceStatistics.isEmpty())
                    list.addAll(dailyProduceStatistics.stream()
                            .map(c -> CapacityStatisticsVo.builder()
                                    .dailyId(c.getId())
                                    .stationId(c.getStationId())
                                    .stationCode(c.getStationCode())
                                    .stationName(c.getStationName())
                                    .singleCost(c.getSingleCost())
                                    .operateTime(c.getOperateTime())
                                    .maintenanceChangeTime(c.getMaintenanceChangeTime())
                                    .expectProduceQty(c.getExpectProduceQty())
                                    .actualProduceQty(c.getActualProduceQty())
                                    .defectsQty(c.getDefectsQty())
                                    .produceRate(c.getProduceRate())
                                    .defectsRate(c.getDefectsRate())
                                    .userNo(c.getUserNo())
                                    .realName(c.getRealName())
                                    .startTime(c.getStartTime())
                                    .endTime(c.getEndTime())
                                    .build())
                            .collect(Collectors.toList()));
            }
        }

        Integer configNo = list.size();
        BigDecimal sumCapacity =
                list.stream()
                        .map(CapacityStatisticsVo::getProduceRate)
                        .filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 工作机台配置
        if (StringUtils.isNotBlank(userNo)) {
            UserWorkStation userWorkStation = userWorkStationMapper
                    .selectOne(new QueryWrapper<UserWorkStation>()
                            .eq("user_no", userNo)
                            .eq("date", date)
                            .eq("deleted", 0));

            if (param.getConfigNo() == null) {
                configNo = userWorkStation != null ? userWorkStation.getConfigNo() : 14;
            } else {
                if (userWorkStation != null)
                    userWorkStationMapper.deleteById(userWorkStation.getId());
                userWorkStationMapper.insert(
                        UserWorkStation.builder()
                                .workshopClassId(param.getWorkshopClassId())
                                .userNo(userNo)
                                .realName(param.getRealName())
                                .date(date)
                                .configNo(param.getConfigNo())
                                .build());
                configNo = param.getConfigNo();
            }
        }

        // 排序
        list.sort(
                Comparator
                        .comparing(CapacityStatisticsVo::getUserNo)
                        .thenComparing(c -> c.getStationCode().replace("-", ""))
        );

        return BizResult.success(
                CapacityStatisticsOutVo
                        .builder()
                        .configNo(configNo)
                        .avgCapacity(configNo == 0 ?
                                BigDecimal.ZERO :
                                sumCapacity
                                        .divide(BigDecimal.valueOf(configNo), 2, RoundingMode.HALF_UP))
                        .capacityStatisticsVos(list)
                        .build());
    }

    /**
     * 查询当天当前班次
     *
     * @param list
     */
    public void queryCurrent(String date, WorkshopClasses workshopClass, List<String> userNos, List<CapacityStatisticsVo> list) {
        String lastDay = DateUtil.formatDateToString(
                DateUtil.dateAddDay(
                        DateUtil.formatStringToDate(date, DateUtil.DATE_FORMAT), -1),
                DateUtil.DATE_FORMAT);
        String secondDay = DateUtil.formatDateToString(
                DateUtil.dateAddDay(
                        DateUtil.formatStringToDate(date, DateUtil.DATE_FORMAT), 11),
                DateUtil.DATE_FORMAT);

        String startTime;
        String endTime;

        int startHour = Integer.parseInt(workshopClass.getStartTime().split(":")[0]);
        int endHour = Integer.parseInt(workshopClass.getEndTime().split(":")[0]);
        if (startHour > endHour) {
            // 夜班
            Date compareDate = DateUtil.formatStringToDate(date + " " + workshopClass.getStartTime() + ":00", DateUtil.DEFAULT_DATE_FORMAT);
            if (new Date().compareTo(compareDate) >= 0) {
                // 上半夜
                startTime = date + " " + workshopClass.getStartTime() + ":00";
                endTime = secondDay + " " + workshopClass.getEndTime() + ":00";
            } else {
                // 下半夜
                startTime = lastDay + " " + workshopClass.getStartTime() + ":00";
                endTime = date + " " + workshopClass.getEndTime() + ":00";
            }
        } else {
            // 白班
            startTime = date + " " + workshopClass.getStartTime() + ":00";
            endTime = date + " " + workshopClass.getEndTime() + ":00";
        }

        List<ReportRecord> allReportRecords = reportRecordMapper.selectList(
                new QueryWrapper<ReportRecord>()
                        .in("user_no", userNos)
                        .eq("deleted", 0)
                        .between("create_time", startTime, endTime));

        if (!allReportRecords.isEmpty()) {
            Map<String, List<ReportRecord>> group = allReportRecords.stream().collect(Collectors.groupingBy(ReportRecord::getStationId));
            Set<String> stationIds = group.keySet();

            // 获取维修+改机+打样记录
            Map<String, List<MachineChange>> machineGroup = new HashMap<>();
            Map<String, List<MaintenanceInfo>> maintenanceGroup = new HashMap<>();
            Map<String, List<Proofing>> proofingGroup = new HashMap<>();
            Map<String, List<ChangTimeVo>> changeTimeMap = new HashMap<>();
            List<MaintenanceInfo> maintenanceInfos = maintenanceInfoMapper.selectList(new QueryWrapper<MaintenanceInfo>()
                    .eq("finish", 1)
                    .in("station_id", stationIds)
                    .between("maintenance_time", startTime, endTime)
            );
            if (!maintenanceInfos.isEmpty())
                maintenanceGroup.putAll(maintenanceInfos.stream().collect(Collectors.groupingBy(MaintenanceInfo::getStationId)));
            List<Proofing> proofings = proofingMapper.selectList(new QueryWrapper<Proofing>()
                    .eq("finish", 1)
                    .in("station_id", stationIds)
                    .between("proofing_time", startTime, endTime)
            );
            if (!proofings.isEmpty())
                proofingGroup.putAll(proofings.stream().collect(Collectors.groupingBy(Proofing::getStationId)));
            List<MachineChange> machineChanges = machineChangeMapper.selectList(new QueryWrapper<MachineChange>()
                    .eq("finish", 1)
                    .in("station_id", stationIds)
                    .between("change_time", startTime, endTime)
                    .orderByAsc("change_time")
            );
            if (!machineChanges.isEmpty()) {
                machineGroup.putAll(machineChanges.stream().collect(Collectors.groupingBy(MachineChange::getStationId)));

                for (Map.Entry<String, List<MachineChange>> entry : machineGroup.entrySet()) {
                    String stationId = entry.getKey();
                    List<MachineChange> changes = entry.getValue();
                    changes.sort(Comparator.comparing(MachineChange::getChangeTime));
                    // 改机分组
                    List<ChangTimeVo> changeTimeList = new ArrayList<>();
                    changeTimeList.add(ChangTimeVo.builder().changeTime(startTime).build());
                    changeTimeList.addAll(
                            changes.stream()
                                    .map(c -> ChangTimeVo.builder()
                                            .changeTime(c.getChangeTime()).machineChange(c).build())
                                    .collect(Collectors.toList())
                    );
                    changeTimeList.add(ChangTimeVo.builder().changeTime(endTime).build());
                    changeTimeMap.put(stationId, changeTimeList);
                }
            }

            // 获取编制检修记录
            List<SpotCheck> spotChecks = spotCheckMapper.selectList(
                    new QueryWrapper<SpotCheck>()
                            .in("station_id", stationIds)
                            .eq("deleted", 0)
                            .between("create_time", startTime, endTime));
            Map<String, List<SpotCheck>> stationSpotCheckGroup = new HashMap<>();
            if (!spotChecks.isEmpty())
                stationSpotCheckGroup.putAll(spotChecks.stream().collect(Collectors.groupingBy(SpotCheck::getStationId)));

            Map<String, List<ReportRecord>> userNoGroup = allReportRecords.stream().collect(Collectors.groupingBy(ReportRecord::getUserNo));
            for (Map.Entry<String, List<ReportRecord>> userNoEntry : userNoGroup.entrySet()) {
                String userNo = userNoEntry.getKey();
                List<ReportRecord> reportRecords = userNoEntry.getValue();

                Map<String, List<ReportRecord>> stationReportGroup = reportRecords.stream().collect(Collectors.groupingBy(ReportRecord::getStationId));
                for (Map.Entry<String, List<ReportRecord>> entry : stationReportGroup.entrySet()) {
                    String stationId = entry.getKey();
                    List<ReportRecord> reports = entry.getValue();

                    StationVo stationById = commonUtil.getStationById(stationId);
                    String realName = reports.get(0).getRealName();
                    List<ChangTimeVo> changeTimeList = changeTimeMap.get(stationId);
                    if (changeTimeList == null) {
                        // 单只耗时
                        Double singleCostMinute = machineChangeMapper.selectLatestSingleCost(stationId, endTime);

                        BigDecimal singleCost = singleCostMinute == null ?
                                null :
                                BigDecimal.valueOf(singleCostMinute)
                                        .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);

                        BigDecimal maintenanceChangeTime = BigDecimal.ZERO;
                        List<MachineChange> changes = machineGroup.get(stationId);
                        if (changes != null)
                            maintenanceChangeTime = maintenanceChangeTime.add(changes.stream().map(MachineChange::getSpendTime).reduce(BigDecimal.ZERO, BigDecimal::add));
                        List<MaintenanceInfo> maintenances = maintenanceGroup.get(stationId);
                        if (maintenances != null)
                            maintenanceChangeTime = maintenanceChangeTime.add(maintenances.stream().map(MaintenanceInfo::getSpendTime).reduce(BigDecimal.ZERO, BigDecimal::add));
                        List<Proofing> proofingList = proofingGroup.get(stationId);
                        if (proofingList != null)
                            maintenanceChangeTime = maintenanceChangeTime.add(proofingList.stream().map(Proofing::getSpendTime).reduce(BigDecimal.ZERO, BigDecimal::add));
                        // 修机器时间
                        maintenanceChangeTime = maintenanceChangeTime.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);

                        // 运转时间
                        BigDecimal operateTime = BigDecimal.valueOf(60 * 12 - 15 * 2).subtract(maintenanceChangeTime);

                        // 预计产能
                        BigDecimal expectProduceQty = null;
                        if (singleCost != null)
                            expectProduceQty = operateTime.divide(singleCost, 2, RoundingMode.HALF_UP)
                                    .divide(BigDecimal.valueOf(2), 2, RoundingMode.HALF_UP);

                        // 实际产量
                        BigDecimal actualProduceQty = reports.stream().map(ReportRecord::getBookJobQty).reduce(BigDecimal.ZERO, BigDecimal::add);

                        // 不良数
                        BigDecimal defectsQty = BigDecimal.ZERO;
                        List<SpotCheck> spots = stationSpotCheckGroup.get(stationId);
                        if (spots != null)
                            defectsQty = BigDecimal.valueOf(spots.stream().map(SpotCheck::getRejectQty).reduce(0, Integer::sum));

                        // 产能效率
                        BigDecimal produceRate = null;
                        if (expectProduceQty != null)
                            produceRate = actualProduceQty.multiply(BigDecimal.valueOf(100)).divide(expectProduceQty, 2, RoundingMode.HALF_UP);

                        // 不良率
                        BigDecimal defectsRate = null;
                        if (actualProduceQty.compareTo(BigDecimal.ZERO) != 0)
                            defectsRate = defectsQty.multiply(BigDecimal.valueOf(100)).divide(actualProduceQty, 2, RoundingMode.HALF_UP);

                        list.add(CapacityStatisticsVo.builder()
                                .stationId(stationById == null ? null : stationById.getId())
                                .stationCode(stationById == null ? null : stationById.getStationCode())
                                .stationName(stationById == null ? null : stationById.getStationName())
                                .singleCost(singleCost)
                                .operateTime(operateTime)
                                .maintenanceChangeTime(maintenanceChangeTime)
                                .expectProduceQty(expectProduceQty)
                                .actualProduceQty(actualProduceQty)
                                .defectsQty(defectsQty)
                                .produceRate(produceRate)
                                .defectsRate(defectsRate)
                                .userNo(userNo)
                                .realName(realName)
                                .startTime(startTime)
                                .endTime(endTime)
                                .build());
                    } else {
                        // 改机存在
                        BigDecimal restTime = BigDecimal.valueOf(15 * 2);
                        String timeStart = null;
                        String timeEnd;
                        ChangTimeVo preVo = null;
                        for (int i = 0; i < changeTimeList.size(); i++) {
                            ChangTimeVo changTimeVo = changeTimeList.get(i);
                            if (timeStart == null) {
                                timeStart = changTimeVo.getChangeTime();
                                preVo = changTimeVo;
                                continue;
                            }

                            timeEnd = changTimeVo.getChangeTime();
                            // 获取对应时间段的报工记录
                            Date timeStartDate = DateUtil.formatStringToDate(timeStart);
                            Date timeEndDate = DateUtil.formatStringToDate(timeEnd);

                            List<ReportRecord> filter = reports.stream()
                                    .filter(obj -> {
                                        Date objDate = obj.getCreateTime();
                                        return objDate.compareTo(timeStartDate) >= 0 && objDate.compareTo(timeEndDate) < 0;
                                    })
                                    .collect(Collectors.toList());

                            if (filter.isEmpty()) {
                                timeStart = changTimeVo.getChangeTime();
                                preVo = changTimeVo;
                                continue;
                            }

                            /*
                             * 报工处理
                             */

                            // 单只耗时
                            Double singleCostMinute = machineChangeMapper.selectLatestSingleCost(stationId, timeEnd);
                            BigDecimal singleCost = singleCostMinute == null ?
                                    null :
                                    BigDecimal.valueOf(singleCostMinute)
                                            .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);

                            BigDecimal maintenanceChangeTime = BigDecimal.ZERO;
                            // 改机时间
                            MachineChange machineChange = preVo.getMachineChange();
                            if (machineChange != null)
                                maintenanceChangeTime = maintenanceChangeTime.add(machineChange.getSpendTime());
                            // 维修时间
                            List<MaintenanceInfo> maintenances = maintenanceGroup.get(stationId);
                            if (maintenances != null) {
                                List<MaintenanceInfo> filterMaintenanceInfo = maintenances.stream()
                                        .filter(obj -> {
                                            Date objDate = DateUtil.formatStringToDate(obj.getMaintenanceTime());
                                            return objDate.compareTo(timeStartDate) >= 0 && objDate.compareTo(timeEndDate) < 0;
                                        })
                                        .collect(Collectors.toList());
                                if (!filterMaintenanceInfo.isEmpty())
                                    maintenanceChangeTime = maintenanceChangeTime
                                            .add(filterMaintenanceInfo.stream()
                                                    .map(MaintenanceInfo::getSpendTime)
                                                    .reduce(BigDecimal.ZERO, BigDecimal::add));
                            }
                            // 打样时间
                            List<Proofing> proofingList = proofingGroup.get(stationId);
                            if (proofingList != null) {
                                List<Proofing> filterProofingList = proofingList.stream()
                                        .filter(obj -> {
                                            Date objDate = DateUtil.formatStringToDate(obj.getProofingTime());
                                            return objDate.compareTo(timeStartDate) >= 0 && objDate.compareTo(timeEndDate) < 0;
                                        })
                                        .collect(Collectors.toList());
                                if (!filterProofingList.isEmpty())
                                    maintenanceChangeTime = maintenanceChangeTime
                                            .add(filterProofingList.stream()
                                                    .map(Proofing::getSpendTime)
                                                    .reduce(BigDecimal.ZERO, BigDecimal::add));
                            }
                            // 修机器时间
                            maintenanceChangeTime = maintenanceChangeTime.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);

                            // 运转时间
                            Long intervalMinutes = DateUtil.intervalMinutes(timeStart, timeEnd);
                            BigDecimal operateTime =
                                    BigDecimal.valueOf(intervalMinutes)
                                            .subtract(maintenanceChangeTime);
                            if (restTime != null) {
                                operateTime = operateTime.subtract(restTime);
                                restTime = null;
                            }

                            // 预计产能
                            BigDecimal expectProduceQty = null;
                            if (singleCost != null)
                                expectProduceQty = operateTime.divide(singleCost, 2, RoundingMode.HALF_UP)
                                        .divide(BigDecimal.valueOf(2), 2, RoundingMode.HALF_UP);

                            // 实际产量
                            BigDecimal actualProduceQty = filter.stream().map(ReportRecord::getBookJobQty).reduce(BigDecimal.ZERO, BigDecimal::add);

                            // 不良数
                            BigDecimal defectsQty = BigDecimal.ZERO;
                            List<SpotCheck> spots = stationSpotCheckGroup.get(stationId);
                            if (spots != null) {
                                List<SpotCheck> filterSpots = spots.stream()
                                        .filter(obj -> {
                                            Date objDate = obj.getCreateTime();
                                            return objDate.compareTo(timeStartDate) >= 0 && objDate.compareTo(timeEndDate) < 0;
                                        })
                                        .collect(Collectors.toList());
                                if (!filterSpots.isEmpty())
                                    defectsQty = BigDecimal.valueOf(filterSpots.stream().map(SpotCheck::getRejectQty).reduce(0, Integer::sum));
                            }

                            // 产能效率
                            BigDecimal produceRate = null;
                            if (expectProduceQty != null)
                                produceRate = actualProduceQty.multiply(BigDecimal.valueOf(100)).divide(expectProduceQty, 2, RoundingMode.HALF_UP);

                            // 不良率
                            BigDecimal defectsRate = null;
                            if (actualProduceQty.compareTo(BigDecimal.ZERO) != 0)
                                defectsRate = defectsQty.multiply(BigDecimal.valueOf(100)).divide(actualProduceQty, 2, RoundingMode.HALF_UP);


                            list.add(CapacityStatisticsVo.builder()
                                    .stationId(stationById == null ? null : stationById.getId())
                                    .stationCode(stationById == null ? null : stationById.getStationCode())
                                    .stationName(stationById == null ? null : stationById.getStationName())
                                    .singleCost(singleCost)
                                    .operateTime(operateTime)
                                    .maintenanceChangeTime(maintenanceChangeTime)
                                    .expectProduceQty(expectProduceQty)
                                    .actualProduceQty(actualProduceQty)
                                    .defectsQty(defectsQty)
                                    .produceRate(produceRate)
                                    .defectsRate(defectsRate)
                                    .userNo(userNo)
                                    .realName(realName)
                                    .startTime(timeStart)
                                    .endTime(timeEnd)
                                    .build());

                            timeStart = timeEnd;
                            preVo = changTimeVo;
                        }
                    }
                }
            }
        }
    }

    /**
     * 查询织造车间用户信息
     *
     * @return
     */
    @Override
    public BizResult<PageResult<StaffInfoVo>> weavingStaff(WeavingStaffPageParam param) {
        PageResult<StaffInfoVo> res = PageResult.<StaffInfoVo>builder()
                .current(0L)
                .size(0L)
                .total(0L)
                .pages(0L)
                .record(new ArrayList<>())
                .build();

        // 织造车间id
        String departmentId = "8B643D9A-8EF0-4356-8C9B-AEDA00A783E0";
        QueryWrapper<Operator> queryWrapper = new QueryWrapper<Operator>()
                .eq("DepartmentGuid", departmentId)
                .eq("IsDeleted", 0)
                .orderByAsc("UserNo");
        if (StringUtils.isNotBlank(param.getQ()))
            queryWrapper.and(c -> c.like("UserNo", param.getQ()).or().like("RealName", param.getQ()));

        Page<Operator> operators = operatorMapper
                .selectPage(new Page<>(param.getCurrent(), param.getSize()), queryWrapper);

        res.setTotal(operators.getTotal());
        res.setPages(operators.getPages());
        res.setSize(param.getSize());
        res.setCurrent(param.getCurrent());
        res.setRecord(operators.getRecords().stream()
                .map(c -> StaffInfoVo.builder()
                        .userNo(c.getUserNo())
                        .realName(c.getRealName())
                        .build())
                .filter(c -> c.getUserNo().length() <= 3)
                .collect(Collectors.toList()));
        return BizResult.success(res);
    }

    /**
     * 单月产能统计
     *
     * @param param
     * @return
     */
    @Override
    public BizResult<List<MonthDailyDataVo>> monthDailyStatistics(MonthDailyStatisticsParam param) {
        List<DailyProduceStatistics> dailyProduceStatistics = dailyProduceStatisticsMapper.selectList(
                new QueryWrapper<DailyProduceStatistics>()
                        .eq("user_no", param.getUserNo())
                        .likeRight("date", param.getYearMonth())
        );

        List<MonthDailyDataVo> list = new ArrayList<>();
        if (!dailyProduceStatistics.isEmpty()) {
            Map<String, List<DailyProduceStatistics>> dateGroup = dailyProduceStatistics.stream()
                    .collect(Collectors.groupingBy(DailyProduceStatistics::getDate));

            for (Map.Entry<String, List<DailyProduceStatistics>> entry : dateGroup.entrySet()) {
                String date = entry.getKey();
                List<DailyProduceStatistics> daily = entry.getValue();

                Integer configNo = 14;
                UserWorkStation userWorkStation = userWorkStationMapper
                        .selectOne(new QueryWrapper<UserWorkStation>()
                                .eq("user_no", param.getUserNo())
                                .eq("date", date)
                                .eq("deleted", 0));
                if (userWorkStation != null)
                    configNo = userWorkStation.getConfigNo();

                BigDecimal avgProduce = daily.stream().map(c -> c.getProduceRate() == null ? BigDecimal.ZERO : c.getProduceRate())
                        .reduce(BigDecimal.ZERO, BigDecimal::add)
                        .divide(BigDecimal.valueOf(configNo), 2, RoundingMode.HALF_UP);
                BigDecimal avgDefects = daily.stream().map(c -> c.getDefectsRate() == null ? BigDecimal.ZERO : c.getDefectsRate())
                        .reduce(BigDecimal.ZERO, BigDecimal::add)
                        .divide(BigDecimal.valueOf(configNo), 2, RoundingMode.HALF_UP);

                BigDecimal dailyCapacityRate = avgProduce
                        .multiply(BigDecimal.valueOf(100L).subtract(avgDefects))
                        .divide(BigDecimal.valueOf(100L))
                        .setScale(2, RoundingMode.HALF_UP);

                list.add(MonthDailyDataVo.builder()
                        .date(date)
                        .dailyProduceRate(avgProduce.toString())
                        .dailyDefectsRate(avgDefects.toString())
                        .dailyCapacityRate(dailyCapacityRate.toString())
                        .build());
            }
        }

        list.sort(Comparator.comparing(MonthDailyDataVo::getDate));
        return BizResult.success(list);
    }

    /**
     * 生成每日统计
     * @param param
     * @return
     */
    @Override
    public BizResult<?> generateDailyStatistics(CapacityStatisticsParam param) {
        List<CapacityStatisticsVo> list = new ArrayList<>();

        String userNo = param.getUserNo();
        String date = param.getDate();
        WorkshopClasses workshopClasses = workshopClassesMapper
                .selectById(param.getWorkshopClassId());

        // 多员工配置
        List<String> userNos = new ArrayList<>();
        if (StringUtils.isNotBlank(userNo))
            userNos.add(userNo);
        else {
            WeavingStaffPageParam weavingStaffPageParam = new WeavingStaffPageParam();
            weavingStaffPageParam.setCurrent(1L);
            weavingStaffPageParam.setSize(9999L);
            BizResult<PageResult<StaffInfoVo>> weavingStaff = this.weavingStaff(weavingStaffPageParam);
            if (weavingStaff.getData() != null && !weavingStaff.getData().getRecord().isEmpty())
                weavingStaff.getData().getRecord().stream().map(StaffInfoVo::getUserNo).forEach(userNos::add);
        }
        queryCurrent(date, workshopClasses, userNos, list);

        if (!list.isEmpty()) {
            List<DailyProduceStatistics> collect = list.stream().map(c -> DailyProduceStatistics.builder()
                    .date(date)
                    .workshopClassId(param.getWorkshopClassId())
                    .stationId(c.getStationId())
                    .stationCode(c.getStationCode())
                    .stationName(c.getStationName())
                    .singleCost(c.getSingleCost())
                    .operateTime(c.getOperateTime())
                    .maintenanceChangeTime(c.getMaintenanceChangeTime())
                    .expectProduceQty(c.getExpectProduceQty())
                    .actualProduceQty(c.getActualProduceQty())
                    .defectsQty(c.getDefectsQty())
                    .produceRate(c.getProduceRate())
                    .defectsRate(c.getDefectsRate())
                    .userNo(c.getUserNo())
                    .realName(c.getRealName())
                    .startTime(c.getStartTime())
                    .endTime(c.getEndTime())
                    .build()).collect(Collectors.toList());
            dailyProduceStatisticsService.saveBatch(collect);
        }


        return BizResult.success();
    }

    /**
     * 单日产能更新
     * @param param
     * @return
     */
    @Override
    public BizResult<?> updateCapacityStatistics(UpdateCapacityStatisticsParam param) {
        if (StringUtils.isBlank(param.getDailyId()))
            return BizResult.fail("当日数据不允许修改");

        DailyProduceStatistics dailyProduceStatistics = dailyProduceStatisticsMapper.selectById(param.getDailyId());
        if (dailyProduceStatistics != null) {
            if (param.getActualProduceQty() != null)
                dailyProduceStatistics.setActualProduceQty(param.getActualProduceQty());
            if (param.getDefectsQty() != null)
                dailyProduceStatistics.setDefectsQty(param.getDefectsQty());


            // 产能效率
            if (dailyProduceStatistics.getExpectProduceQty() != null)
                dailyProduceStatistics.setProduceRate(
                        dailyProduceStatistics.getActualProduceQty()
                                .multiply(BigDecimal.valueOf(100))
                                .divide(dailyProduceStatistics.getExpectProduceQty(), 2, RoundingMode.HALF_UP));

            // 不良率
            if (dailyProduceStatistics.getActualProduceQty().compareTo(BigDecimal.ZERO) != 0)
                dailyProduceStatistics.setDefectsRate(
                        dailyProduceStatistics.getDefectsQty()
                                .multiply(BigDecimal.valueOf(100))
                                .divide(dailyProduceStatistics.getActualProduceQty(), 2, RoundingMode.HALF_UP));

            dailyProduceStatisticsMapper.updateById(dailyProduceStatistics);
        }

        return BizResult.success();
    }


}
